/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>

#include "client_base.h"
#include "se_base_services_defines.h"
#include "tee_service_public_mock.h"
#include "tee_sharemem_ops_mock.h"

namespace OHOS {
namespace SeBaseServices {
namespace UnitTest {
using namespace testing;

TEST(ClientBaseTest, SendRequestToServerTestNullInput)
{
    // the input and output buffer could be nullptr
    uint32_t ret = SendRequestToServer(0, nullptr, 0, nullptr, nullptr);
    EXPECT_EQ(ret, SUCCESS);
}

TEST(ClientBaseTest, SendRequestToServerTestCaseShareMemAllocError)
{
    // mock the sharemem alloc err
    TeeAllocSharememAux mock;
    EXPECT_CALL(mock, tee_alloc_sharemem_aux).WillRepeatedly(Return(nullptr));

    // the input and output buffer could be nullptr
    uint32_t ret = SendRequestToServer(0, nullptr, 0, nullptr, nullptr);

    // now will return MEM_ALLOC_ERR
    EXPECT_EQ(ret, MEM_ALLOC_ERR);
}

TEST(ClientBaseTest, SendRequestToServerTestWillSuccess)
{
    constexpr uint32_t INPUT_LEN = 128;
    constexpr uint32_t OUTPUT_LEN = 128;
    uint8_t data[INPUT_LEN] = {0};
    uint8_t reply[OUTPUT_LEN] = {0};
    uint32_t replyLen = OUTPUT_LEN;
    uint32_t ret = SendRequestToServer(0, data, INPUT_LEN, reply, &replyLen);
    EXPECT_EQ(ret, SUCCESS);
}

TEST(ClientBaseTest, SendRequestToServerTestTooBigInputParaSize)
{
    constexpr uint32_t INPUT_LEN = 65535; // big input len
    constexpr uint32_t OUTPUT_LEN = 128;
    uint8_t data[INPUT_LEN] = {0};
    uint8_t reply[OUTPUT_LEN] = {0};
    uint32_t replyLen = OUTPUT_LEN;
    uint32_t ret = SendRequestToServer(0, data, INPUT_LEN, reply, &replyLen);
    EXPECT_EQ(ret, INVALID_PARA_ERR_SIZE);
}

TEST(ClientBaseTest, SendRequestToServerTestCaseTeeIpcTransmitError)
{
    constexpr uint32_t ERR_RET = 0x99008800;
    auto func = [](const char *, uint32_t, const tee_service_ipc_msg *, uint32_t,
                    tee_service_ipc_msg_rsp *rspMsg) -> void {
        // make rspMsg return error
        rspMsg->ret = ERR_RET;
    };

    TeeCommonIpcProcCmd mock;
    EXPECT_CALL(mock, tee_common_ipc_proc_cmd).WillOnce(Invoke(func));

    // the input and output buffer could be nullptr
    uint32_t ret = SendRequestToServer(0, nullptr, 0, nullptr, nullptr);
    EXPECT_EQ(ret, ERR_RET);
}

TEST(ClientBaseTest, SendRequestToServerTestCaseTeeIpcTransmitSuccess)
{
    constexpr uint32_t CMD = 4096;
    constexpr uint32_t INPUT_LEN = 128;
    constexpr uint32_t OUTPUT_LEN = 256;
    constexpr uint32_t MAX_DATA_LEN = 512;

    auto func = [](const char *, uint32_t, const tee_service_ipc_msg *sndMsg, uint32_t,
                    tee_service_ipc_msg_rsp *rspMsg) -> void {
        auto cmd = CMD;
        EXPECT_EQ(sndMsg->args_data.arg0, cmd);

        auto maxbuffLen = MAX_DATA_LEN;
        EXPECT_EQ(sndMsg->args_data.arg1, maxbuffLen);
        EXPECT_EQ(sndMsg->args_data.arg2, 128);
        EXPECT_NE(sndMsg->args_data.arg3, 0);

        char *buff = reinterpret_cast<char *>(sndMsg->args_data.arg3);
        buff[0] = 'a';
        buff[1] = 'b';
        buff[2] = 'c';
        buff[3] = 0;
        rspMsg->msg.args_data.arg4 = 4;
        rspMsg->ret = 0;
    };

    TeeCommonIpcProcCmd mock;
    EXPECT_CALL(mock, tee_common_ipc_proc_cmd).WillOnce(Invoke(func));

    uint8_t data[INPUT_LEN] = {0};
    uint8_t reply[OUTPUT_LEN] = {0};
    uint32_t replyLen = OUTPUT_LEN;
    uint32_t ret = SendRequestToServer(CMD, data, INPUT_LEN, reply, &replyLen);
    EXPECT_EQ(ret, SUCCESS);
    EXPECT_EQ(replyLen, 4);
    EXPECT_EQ(reply[0], 'a');
    EXPECT_EQ(reply[1], 'b');
    EXPECT_EQ(reply[2], 'c');
    EXPECT_EQ(reply[3], 0);
}
} // namespace UnitTest
} // namespace SeBaseServices
} // namespace OHOS